package edu.ua.bmr.android;
import java.util.ArrayList;
import java.util.HashMap;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;

/**
 * This Activity is where the user will go when searching the course catalog.
 * Also, this the only point in the application where a user can add courses.
 * @author OEP
 *
 */
public class SearchActivity extends ListActivity implements Runnable {
	private static final String TAG = "SearchActivity";
	
	private EditText mSearchBox;
	private ImageButton mSearchButton;
	private Dialog mProgressBox;
	private String mSearchTerm;
	private ArrayList< HashMap<String,String> > mData;
	private boolean mThreadIsWorking = false;
	
	/** What to do when a key has been typed into the search box */
	private OnKeyListener mKeyPressed = new OnKeyListener() {

		public boolean onKey(View v, int keyCode, KeyEvent event) {
			// TODO: In the scary future, we could add as-you-type search suggestions.
			switch(keyCode) {
			case KeyEvent.KEYCODE_ENTER:
				doSearch();
			}
			return false;
		}
		
	};
	
	/** What to do when a search button has been pressed */
	private OnClickListener mSearchButtonPressed = new OnClickListener() {

		public void onClick(View v) {
			if(v != mSearchButton) return;
			doSearch();
		}
		
	};
	
	/**
	 * If the user clicks an item in the list, we'll
	 * simply take them to view more information about
	 * it.
	 */
	private OnItemClickListener mItemClicked = new OnItemClickListener() {

		public void onItemClick(AdapterView parent, View view, int position, long id) {
			ListView list = getListView();
			
			// We clicked a class. We should pass this object
			// to ClassActivity.
			HashMap<String,String> map =
				(HashMap<String, String>) list.getItemAtPosition(position);

			
			// Construct the intent needed for viewing a class...
			Intent intent = BMR.getClassViewIntent(SearchActivity.this, map);
			
			// Start the next activity.
			startActivityForResult(intent, 0);
		}
		
	};
	
	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		
		this.setContentView(R.layout.act_search);
		this.setTitle( R.string.search_for_classes );
		
		// Load up dems user interfaces.
		mSearchBox = (EditText) this.findViewById(R.id.act_search_searchbox);
		mSearchButton = (ImageButton) this.findViewById(R.id.act_search_button);
		
		// Set up dem listeners.
		mSearchButton.setOnClickListener(mSearchButtonPressed);
		mSearchBox.setOnKeyListener(mKeyPressed);
		getListView().setOnItemClickListener(mItemClicked);
	}
	
	@Override
	public void onActivityResult(int request, int result, Intent intent) {
		super.onActivityResult(request, result, intent);
		
		String crn = intent.getStringExtra(BMR.TABLE_CLASSES_CRN);
		
		if(result == ClassActivity.RESULT_DIRTY) {
			// Update the search cache
			for(HashMap<String,String> item : mData) {
				if(item.get(BMR.TABLE_CLASSES_CRN).compareTo(crn) == 0) {
					Log.i(TAG, "Updating search result CRN: " + crn);
					item.put(BMR.KEYWORD_REGISTERED, intent.getStringExtra(BMR.KEYWORD_REGISTERED));
				}
			}
			
			// Tell the SemesterActivity that called us that 
			// it will need to update the classes.
			setResult(ClassActivity.RESULT_DIRTY);
		}
	}
	
	/**
	 * Start up a thread (if there isn't already one) to search for classes.
	 * Will spawn a ProgressDialog.
	 * @param term, the search term
	 */
	private void doSearch() {
		// Get the term that the user entered.
		Editable text = mSearchBox.getText();
		String s = text.toString();

		// Hide the soft keyboard.
		InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
		imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
		
		// Do something if the user entered anything at all.
		if(s.length() == 0 && mThreadIsWorking == false) {
			// Scold the user because he's a silly boy and forgot to enter the search term.
			Builder builder = new AlertDialog.Builder(SearchActivity.this);
			builder.setTitle(R.string.blank_field);
			builder.setMessage(R.string.search_term_required);
			builder.setPositiveButton(R.string.button_ok, null);
			builder.show();
			return;
		}
		else if(mThreadIsWorking == true) return;
		
		mThreadIsWorking = true;
		mSearchTerm = s;
		
		// String resolving will be needed
		Resources r = this.getResources();
		
		mProgressBox = BMR.showProgressDialog(this, R.string.please_wait, R.string.searching_for_classes);
		
		// Go thread go!
		Thread t = new Thread(this);
		t.start();
	}

	/**
	 * Handler will wait for the thread to send a message. On a success (indicated by Message.arg1 == 1),
	 * the Handler will update the ListView with the updated data.
	 */
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			mProgressBox.dismiss();
			switch(msg.arg1) {
			case 1:
				ListView v = SearchActivity.this.getListView();
				v.setAdapter(new SimpleAdapter(SearchActivity.this, mData, R.layout.classitem, BMR.CLASSLIST_FIELDS, BMR.CLASSLIST_VIEWS));
				break;
				
			default:
				// An exception was thrown. Build a dialog to tell the user.
				Builder builder = new AlertDialog.Builder(SearchActivity.this);
				builder.setTitle(R.string.alert_error);
				builder.setMessage(msg.arg2);
				builder.setPositiveButton(R.string.button_ok, null);
				builder.show();
				break;
			}
		}
	};
	
	/**
	 * This thread will try and fetch a result for us in the background. It will send a Message object
	 * to mHandler to report the result. It will manipulate 'mData' if the data returned was good.
	 */
	public void run() {
		// Get the instance of Session
		Session s = Session.getInstance();
		
		// Allocate our message object
		Message msg = new Message();
		
		try {
			// Assign the new data.
			mData = s.searchClasses(mSearchTerm);
			
			// We succeeded.
			msg.arg1 = 1;
			mHandler.sendMessage(msg);
		} catch (BMRException e) {
			// We failed. Send over the errors.
			msg.arg1 = 0;
			msg.arg2 = e.getResourceId();
			mHandler.sendMessage(msg);
		}
		
		
		// Thread is all done. A new one may be launched.
		mThreadIsWorking = false;
	}	
}
